package com.fdm.model.DAO;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.TreeMap;
import com.fdm.model.accounts._Account;
import com.fdm.model.exceptions.BankManagerException;
import com.fdm.model.exceptions.DAOException;
import com.fdm.model.exceptions.BankPropertiesException;
import com.fdm.model.properties.BinaryProperties;

public class BinaryDAO implements _AccountDAO
{
	private static Map<Integer,_Account> accounts = new TreeMap<Integer,_Account>();
	private static String filename ="..\\" +new BinaryProperties().getFilename();
	
	public BinaryDAO() throws BankPropertiesException, DAOException
	{
		accounts = ByteCodeRead(filename);
		
		if (accounts == null)
		{
			accounts=new TreeMap<Integer,_Account>();
		}
	}

	@Override
	public _Account retrieve(int accountNumber) throws DAOException 
	{
		return accounts.get(accountNumber);
	}

	@Override
	public void delete(int accountNumber) throws DAOException 
	{
		accounts.remove(accountNumber);
		ByteCodeWrite(accounts);
	}

	@Override
	public void update(int accountNumber, Double newValue) throws DAOException 
	{
		Map<String,Object> parameters = new TreeMap<String, Object>();
		parameters.put("balance", newValue);
		try {
			retrieve(accountNumber).setAttributes(parameters);
		} catch (BankManagerException e) {
			throw new DAOException();
		}
		ByteCodeWrite(accounts);
	}

	@Override
	public void create(_Account newAccount) throws DAOException 
	{	
		accounts.put(newAccount.getAccountNumber(), newAccount);
		ByteCodeWrite(accounts);
	}

	@Override
	public List<_Account> retrieveAll() 
	{
		List<_Account> accountList = new ArrayList<_Account>();
		for(_Account account: accounts.values())
		{
			accountList.add(account);
		}
		return accountList;
	}

	@Override
	public String getStorageType() 
	{
		return "BINARY";
	}
	
	private Map<Integer,_Account> ByteCodeRead(String filename) throws DAOException, BankPropertiesException
	{	
		Map<Integer,_Account> map = new TreeMap<Integer,_Account>();
		try
		{
			InputStream IS = this.getClass().getClassLoader().getResourceAsStream(filename);
			ObjectInputStream OIS = new ObjectInputStream(IS);
			map = (Map<Integer,_Account>) OIS.readObject();
			IS.close();
			OIS.close();
		}
		catch (FileNotFoundException e1){
			throw new BankPropertiesException();
		} 
		catch (IOException e) {
			throw new DAOException();
		} 
		catch (ClassNotFoundException e) {
			throw new DAOException();
		} 
		return map;
	}
	
	private void ByteCodeWrite(Map<Integer,_Account> newAccounts) throws DAOException
	{
		
		try {
			URL url = this.getClass().getClassLoader().getResource(filename);
			FileOutputStream FOS = new FileOutputStream(url.toURI().getPath());
			ObjectOutputStream OOS = new ObjectOutputStream(FOS);
			OOS.writeObject(newAccounts);
			OOS.close();
			FOS.close();
		}
		catch (FileNotFoundException e1) {
			throw new DAOException();
		}
		catch (IOException e) {
			throw new DAOException();
		} catch (URISyntaxException e) {

		}
	}

	@Override
	public int getMaxAccountNumber() {
		try{
			return ((TreeMap<Integer, _Account>) accounts).lastKey();
		}catch(NoSuchElementException e)
		{
			return 10000;
		}
	}
}
